Some years ago I used to attend a day center for the mentally disabled, where I attempted to encourage some to make use of a computer. I sometimes surprised the staff with some success in helping those who appeared quite incapable. We were amazed to find the one most skilled at handling a racing car in a program was a young woman, who would often lean over when the car image needed to negotiate a tight curve in the racetrack. Furthermore it was not always the women who had the patience to spend some time at practicing typing.
Two of the unfortunate people, though probably very intelligent, were severely paralysed, and unable to speak. Both made use of a rather crude keyboard strapped to their wheelchairs, able to emit speech sounds. I therefore decided to try to create a Qbasic program to try to help, using an old DOS speech synthesizer, which I have now upgraded using LB thanks to the invaluable help provided by Stefan Pendl.
You will see the user has the choice of activating the set phrases using either the mouse or a joystick. However due to the wide variations in the way different joysticks behave, those attempting to make serious use of this option in an improved version of this program, may need to make certain changes to match a suitable joystick or even tracker-ball. Alternatively it will accept keyboard input and will also produce a printout. The program starts the usual way devised by Stefan to test for the presence in the system for the necessary MS Agents to allow speech to be produced, and provide a warning if there is a problem.
Rather than incorporating some complex method of editing the phrases in PHRASES.DAT, I decided to make use of NOTEPAD, since the file is pure ASCII, and this allows changes to be made independently of the program. As the program caters for the smaller 800 x 600 display in case of poor eyesight, I adopted the practice of providing a background for larger screen displays.
I am sure those with a medical knowledge of dealing with these people could make a number of improvements to this program if they wished. Comments always welcome in the forum.
Editor's Note: For a more indepth discussion and explanation of John White's Text to Speech dll's, see [Demo: Using a Speech Synthesizer] by [Gordon Sweet], [Liberty BASIC Newsletter #117] and [Text to Speech with Liberty BASIC] by Stefan Pendl, [Liberty BASIC Newsletter #118]. These two articles will also provide information about downloading and installing the necessary Microsoft support files and documentation required for speech capability. Since the publications of these two articles, John White has updated the original stm.dll to two separate files: tts.dll (Text to Speech) and ttw.dll (Text to Wavefile). These two files, along with support documentation and John's demo written in Liberty BASIC, can be downloaded at [http://www.yoingco.com/YoingcoDLLs.zip].
' *** NEEDS STM.DLL IN SAME DIRECTORY ***
' -------------------------------------------------------------------------
' Text to Speech testing for using MS Agent and
' based on tts_tool.c by Martin Goebel
' using stm.dll and ttw.dll by John White
' by Stefan Pendl
' Revision History
' ===============
' Version | Date | Name | Reason
' --------|-------------|--------------|-----------------------------------
' 1.0 | 30.Jan.2004 | Stefan Pendl | Initial
nomainwin
WindowWidth=DisplayWidth : WindowHeight=DisplayHeight
open "MS Agent Test" for text_fs as #test
#test "!trapclose [done]" : testok = 0
'constants:
TEXT.BUFFER.SIZE = 5000
'variables to preset:
voiceTotal = 0
'at the very beginning of your app to check if speech is installed:
open "stm.dll" for dll as #speech
speechOpen = 1
rtn = BeginSpeech(TEXT.BUFFER.SIZE)
if rtn = 1 then
voiceTotal = CountVoices()
if voiceTotal > 0 then
testok = 1
goto [done]
else
notice "Speech API 4 Error";chr$(13);_
"Speech API 4 Runtime and/or Voice Engines NOT Installed."
goto [quittest]
end if
else
notice "Speech Library Error";chr$(13);_
"MS Agent Core NOT Installed."
goto [quittest]
end if
'before ending your app:
[quittest]
#test "MS Agent support files are downloadable from [http://www.microsoft.com/msagent/downloads/user.asp]"
#test " "
#test "MS Agent documentation is found at [http://www.microsoft.com/msagent/downloads/developer.asp]"
wait
[done]
if speechOpen = 1 then
rtn = EndSpeech()
close #speech
end if
close #test
if testok = 0 then end
'constants:
TEXT.BUFFER.SIZE = 5000
NEW.TTS.ALWAYS = 1
USE.DEFAULT.VOLUME = 0
USE.DEFAULT.PITCH = 0
USE.DEFAULT.SPEED = 0
USE.TEXT = 0
CLEAR.TEXTSPEECH.BUFFER = 3
'variables to preset:
voiceTotal = 0
currentVoice = 0
voiceNumber = 0
volume = 0
pitch = 0
speed = 0
intro = 1
[startup]
'at the very beginning of your app to check if speech is installed:
open "stm.dll" for dll as #speech
rtn = BeginSpeech(TEXT.BUFFER.SIZE)
if rtn = 1 then
voiceTotal = CountVoices()
if voiceTotal > 0 then
call EnumVoiceData
vdPtr = GetVoiceData(currentVoice)
else
notice "SAPI4 Error";chr$(13);_
"SAPI4 and/or Voice Engines NOT Installed."
goto [quit]
end if
else
notice "Speech Library Error";chr$(13);_
"Library Speech NOT Available."
goto [quit]
end if
' ******** MAIN MENU ********
open "Background" for graphics_fs_nsb as #bg
#bg "trapclose [quit]; down; fill darkgreen; flush"
[menu]
if win = 9 then close #9
bx3 = 0 : bx7 = 0 : jm = 0 : win = 0
ux = 1 : uy = 1
if DisplayWidth > 1000 then ux = 120 : uy = 90
UpperLeftX = ux : UpperLeftY = uy
WindowWidth = 800 : WindowHeight = 580
joyst$="" : jm = 0 : first = 1
WindowWidth = 800 : WindowHeight = 600
button #1, "SPEECH SCREEN", [mquit], UL, 160, 400, 140, 30
button #1, "ALTER PHRASES", [alter], UL, 320, 400, 140, 30
button #1, "ABORT/RESTART", [quit], UL, 480, 400, 140, 30
open "OPTIONS / QUIT" for graphics_nsb as #1
#1 "trapclose [quit]" : win = 1
#1 "cls; fill 150 250 150; backcolor 150 250 150"
#1 "font arial 24 bold; place 300 100" : #1 "\Menu of Options"
DIM PHRASE$(100)
if joyst$<>"" then [rescr]
joyst$ = "OFF"
Speech$ = "Do you wish to use the Joystick"
rtn = SpeakString(USE.TEXT,Speech$,CLEAR.TEXTSPEECH.BUFFER,_
currentVoice,NEW.TTS.ALWAYS,USE.DEFAULT.VOLUME,volume,_
USE.DEFAULT.PITCH,pitch,USE.DEFAULT.SPEED,speed)
j$ = "" : confirm Speech$; j$
if j$ = "yes" then joyst$="ON"
[rescr]
tx1$ = "\You can change or erase any of the phrases, such as using Windows Notepad. "
tx2$ = "\The maximum number of possible phrases is 90, each with a limit of 15 letters."
tx3$ = "\\You can also enter a message using the Keyboard by clicking the KEYS button"
#1 "cls; fill 150 250 150; backcolor 150 250 150"
#1 "font arial 24 bold; place 280 100" : #1 "\Menu of Options"
#1 "font arial 10; place 250 130"
#1 "\Speech Aid by Gordon Sweet Ver. 2.3 October 2005"
#1 "\Speech Function by Stefan Pendl megabit@t-online.at"
#1 "\using STM.dll by' John White http://www.yoingco.com/main.htm"
#1 "font arial 13 bold; color darkred; place 80 200"
#1 tx1$;tx2$;tx3$
#1 "color black; place 120 340"
#1 "\THE JOYSTCK IS ";joyst$;". RESTART THE PROGRAM TO CHANGE THIS."
#1 "flush" : intro = 0
[mhold]
wait
[mquit]
if snd=1 then snd$=""
if first = 1 then first = 0 : goto [start]
close #1 : goto [hold]
[start]
'****** SPEECH SCREEN *******
close #1 : win = 9
if j$ = "yes" then gosub [jsinit] : joyst$ = "ON"
statictext #9.s, snd$, 1, 4, 550, 20
if joyst$="ON" then [set]
button #9, "SPEAK", [speak], UL 560, 4
button #9, "PRINT", [pout], UL 620, 4
button #9, "CLEAR", [clear], UL 680, 4
button #9, "KEYS ", [kbrd], UL 740, 4
[set]
tx$="Left Click or Button to Select, Right Click for Options and Quit"
open tx$ for graphics_nsb as #9
snd=0 : po$=""
#9 "trapclose [quit]; down"
if jm = 0 then
#9 "when leftButtonDown [which]"
#9 "when rightButtonDown [menu]"
end if
snd$="Select phrases below, or click KEYS, then use SPEAK/PRINT/CLEAR"
OPEN "phrases.dat" FOR INPUT AS #2
Count = 0: ok=0
WHILE ok=0
IF EOF(#2) < 0 THEN ok = 1 : GOTO [none]
Count = Count + 1
line input #2, i$ : li=len(i$)
if li>15 then i$=left$(i$,15)
PHRASE$(Count)=i$
[none]
WEND
CLOSE #2
[hold]
gosub [show]
if joyst$="ON" then goto [joyset]
wait
[clear] snd$="" : if joyst$="OFF" then goto [text]
#9 "cls; fill 200 200 100"
gosub [show] : goto [hold]
[top]
if joyst$="OFF" then [hold]
if y<6 or y>20 then [hold]
if x>560 and x<600 then [speak]
if x>620 and x<660 then [pout]
if x>680 and x<720 then [clear]
if x>740 and x<780 then [kbrd]
goto [hold]
[show]
#9 "cls; font fixedsys; fill 200 200 100"
#9 "backcolor darkblue; color white"
h=30 : C=1 : #9 "place 1 30; down"
for row=1 to 18
w=4
for colm=1 to 5
#9 "place ";str$(w);" ";str$(h+20)
phrs=C-1+colm
t$=PHRASE$(phrs)
lt=len(t$)
if lt<16 then t$="\"+" "+t$+space$(16-lt)
if check=1 then #9 "\";str$(C)
#9 t$;
w=w+160
next colm
h=h+30 : C=C+5
next row
print #9.s, "font arial 12 bold; backcolor white; color black"
print #9.s, snd$;
#9 "flush"
return
[which]
if snd=0 then snd$="" : snd=1
if joyst$="OFF" then x=MouseX : y=MouseY
test$=""
if x < 4 or x > 780 then [hold]
if y > 562 then [hold]
if y < 38 then [top]
A = 38 : B = 50 : L = 0
for D = 1 to 18
if y > A and y < B then L = D
A = A + 30 : B = B + 30
next D
if L = 0 then [hold]
L = (L - 1) * 5
A = 4 : B = 138 : K = 0
for D = 1 to 5
if x > A and x < B then K = D
A = A + 160 : B = B + 160
next D
if K = 0 then [hold]
if K = 0 then [hold]
K = K + L
test$ = snd$ + PHRASE$(K) + " "
if len(test$) > 70 then
notice "Tool long! Click SPEAK\PRINT\CLEAR"
goto [hold]
end if
snd$ = test$
[text]
print #9.s, space$(136) : print #9.s, snd$;
goto [hold]
[kbrd]
if bx7 = 1 then close #7
snd = 1 : i$=""
if left$(snd$,4) = "****" then snd$ = ""
WindowWidth = 500 : WindowHeight = 150
UpperLeftX = 180+ux : UpperLeftY = 100+uy
BackgroundColor$ = "green" : ForegroundColor$ = "black"
TextboxColor$ = "white"
tx$="Maximum characters 70 including text already shown"
statictext #7, tx$, 6, 10, 790, 20
textbox #7.tbox1, 10, 30, 470, 25
button #7.default, "Accept", [pass], UL, 100, 70, 100, 25
button #7, "Cancel", [bfin], UL, 300, 70, 100, 25
open "Enter message" for dialog as #7
#7 "trapclose [again]" : #7 "font fixedsys"
[again]
print #7.tbox1, snd$
bx=1 : playwave "ping.wav"
mainH=hWnd(#7) : gosub [boxhold]
wait
[pass]
print #7.tbox1, "!contents? A$"
if len(i$)+len(A$) > 70 then
notice "Exceed Limit!"
goto [again]
end if
snd$=A$+" "
[bfin] bx7=0 : close #7 : goto [text]
[pout]
if left$(snd$,3)="***" then [hold]
lprint snd$;" ";
confirm "Printout now, otherwise later"; po$
if po$="yes" then dump
goto [hold]
[alter]
run "notepad.exe phrases.dat", restore
goto [rescr]
[jsinit]
open "winmm.dll" for dll as #mm
Struct JOYINFO, _
x As long , _ 'x position
y As long , _ 'y position
z As long , _ 'z position
buttons As long 'buttons pushed
JOYSTICK1 = 0 : JOYSTICK2 = 1
timer 50, [checkJoy]
x=400 : y=300 : jm = 1
return
[jloop]
x1=x : y1=y
#9 "backcolor red";
wait
[checkJoy]
READJOYSTICK 1
X=Joy1x : Y=Joy1y : b1=Joy1button1 : b2=Joy1button2
if X<30000 and x>2 then x=x-3
if X>40000 and x<784 then x=x+3
if Y<20000 and y>4 then y=y-3
if Y>40000 and y<566 then y=y+3
#9 "place ";str$(x1);" ";str$(y1);
#9 "rule XOR; circlefilled 3";
#9 "place ";str$(x);" ";str$(y);
#9 "circlefilled 3";
if b1 then gosub [delay] : goto [which]
if b2 then gosub [delay] : goto [speak]
goto [jloop]
[delay]
scan:calldll #kernel32,"Sleep",300 as ulong,r as void
return
[joyset]
#9 "when leftButtonDown [hold]"
#9 "color black; backcolor lightgray; place 560 20" : #9 "\SPEAK"
#9 "place 620 20" : #9 "\PRINT"
#9 "place 680 20" : #9 "\CLEAR"
#9 "place 740 20" : #9 "\KEYS "
goto [jloop]
[quit]
rtn = EndSpeech()
close #speech
intro = 0
if po$<>"" then dump
if bx3 = 1 then close #3
if bx7 = 1 then close #7
if win = 9 then close #9
if win = 1 then close #1
if jm = 1 then close #mm
close #bg
end
[boxhold]
open "user32" for dll as #user ' prevents losing box
toTop=(-1 or 0)
flags=_SWP_NOMOVE or _SWP_NOSIZE
calldll #user,"SetWindowPos",mainH as ushort,toTop as short,_
0 as short,0 as short,0 as short,0 as short,flags as ushort,_
result as void
close #user : return
[speak]
Speech$ = lower$(snd$)
rtn = SpeakString(USE.TEXT,Speech$,CLEAR.TEXTSPEECH.BUFFER,_
currentVoice,NEW.TTS.ALWAYS,USE.DEFAULT.VOLUME,volume,_
USE.DEFAULT.PITCH,pitch,USE.DEFAULT.SPEED,speed)
goto [hold]
'functions:
function BeginSpeech(BufferSize)
calldll #speech, "Begin_Speech", BufferSize as long, BeginSpeech as long
end function
' memory buffer size in bytes; >= 5000 1 ... success; 0 ... error
function GetVoiceData(VoiceIndex)
calldll #speech, "Get_VoiceData",_
VoiceIndex as long, GetVoiceData as long
end function
function SpeakString(SourceFlag,Text$,ClearFlag, VoiceIndex,TTSFlag, VolumeFlag,Volume,PitchFlag,Pitch,SpeedFlag,Speed)
TextBuffer$ = Text$ + chr$(0)
calldll #speech, "Speak_String",_
SourceFlag as long,_
TextBuffer$ as ptr,_
ClearFlag as long,_
VoiceIndex as long,_
TTSFlag as long,_
VolumeFlag as long,_
Volume as long,_
PitchFlag as long,_
Pitch as long,_
SpeedFlag as long,_
Speed as long,_
SpeakString as long
end function
function EndSpeech()
calldll #speech, "End_Speech", EndSpeech as long
end function
'subroutines:
sub EnumVoiceData
calldll #speech, "Enum_VoiceData", result as long
end sub
function CountVoices()
calldll #speech, "Count_Voices", CountVoices as long
end function
' 0 if no voices are installed, else the number of installed voices
The files speechsynthesizer.bas, phrases.dat and stm.dll are included in the zipped archive of this newsletter.